package entity;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;

/**
 * Rappresenta un utente iscritto alla wishlist.
 * Ogni utente ha una lista di oggetti desiderati.
 *
 * @author Rachid Ouchary, Fabio Strocco, Max Passaghe, Marco Tansini.
 * @see{@link entity.Wish}
 */
@Entity
@NamedQueries({
    @NamedQuery(name = Utente.CERCA_PERSONE, query = "SELECT u "
    + "FROM Utente u "
    + "WHERE LOWER(u.username) LIKE :username "
    + "AND LOWER(u.nome) LIKE :nome "
    + "AND LOWER(u.cognome) LIKE :cognome "
    + "AND LOWER(u.mail) LIKE :email "
    + "AND ((:on = TRUE) OR u.username  <> :current) "
    + "ORDER BY u.nome"),

    @NamedQuery(name = Utente.CERCA_AMICI, query = "SELECT a "
    + "FROM Utente u JOIN u.amici a "
    + "WHERE LOWER(a.username) LIKE :username "
    + "AND LOWER(a.nome) LIKE :nome "
    + "AND LOWER(a.cognome) LIKE :cognome "
    + "AND LOWER(a.mail) LIKE :email "
    + "AND LOWER(u.username) = :current "
    + "ORDER BY u.nome"),
            
    @NamedQuery(name = Utente.FIND_ORDERED_WISH, query = "SELECT w "
    + "FROM Utente u, IN(u.wishList) w "
    + "WHERE u.username = :username "
    + "ORDER BY w.priority DESC, w.voto DESC")
})
public class Utente implements Serializable {
    public static final String CERCA_PERSONE = "cercaPersone";
    public static final String CERCA_AMICI = "cercaAmici";
    public static final String FIND_ORDERED_WISH = "findOrderedUserWish";

    private static final long serialVersionUID = 1L;
    @Id
    private String username;
    @Column(nullable = false)
    private String password;
    @Column(nullable = false)
    private String nome;
    @Column(nullable = false)
    private String cognome;
    @Column(nullable = true)
    private String citta;
    @Column(nullable = true)
    private String professione;
    @Column(nullable = false)
    private String mail;
    /*notifiche ???*/
    @OneToMany(fetch = FetchType.LAZY)
    private Set<Utente> amici;
    
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "utente")
    private Set<Wish> wishList;

    /**
     * Crea un nuovo utente.
     */
    public Utente() {
        amici = new HashSet<Utente>();
        wishList = new HashSet<Wish>();
    }

    /**
     * Crea un nuovo utente.
     *
     * @param username lo username dell'utente.
     * @param password la password dell'utente.
     * @param nome il nome dell'utente.
     * @param cognome il cognome dell'utente.
     * @param citta la citt&agrave dell'utente.
     * @param professione la professione dell'utente.
     * @param mail la mail dell'utente.
     */
    public Utente(String username, String password, String nome, String cognome,
            String citta, String professione, String mail) {
        this();
        this.username = username;
        this.password = password;
        this.nome = nome;
        this.cognome = cognome;
        this.citta = citta;
        this.professione = professione;
        this.mail = mail;
    }

    /**
     * Crea un nuovo utente.
     *
     * @param username lo username dell'utente.
     * @param password la password dell'utente.
     * @param nome il nome dell'utente.
     * @param cognome il cognome dell'utente.
     * @param mail la mail dell'utente.
     */
    public Utente(String username, String password, String nome, String cognome,
            String mail) {
        this(username, password, nome, cognome, null, null, mail);
    }

    /**
     * Restituisce la wishlist dell'utente.
     *
     * @return la wishlist dell'utente.
     */
    public Collection<Wish> getWishList() {
        wishList.size();
        return wishList;
    }

    /**
     * Restituisce la lista di amici dell'utente.
     *
     * @return la lista di amici dell'utente.
     */
    public Collection<Utente> getAmici() {
        amici.size();
        return amici;
    }

    /**
     * Restituisce l'e-mail dell'utente.
     *
     * @return l'e-mail dell'utente.
     */
    public String getMail() {
        return mail;
    }

    /**
     * Imposta l'e-mail dell'utente.
     *
     * @param mail l'e-mail dell'utente.
     */
    public void setMail(String mail) {
        this.mail = mail;
    }

    /**
     * Restituisce la professione dell'utente.
     *
     * @return la professione dell'utente.
     */
    public String getProfessione() {
        return (professione == null ? "" : professione);
    }

    /**
     * Imposta la professione dell'utente.
     *
     * @param professione la professione dell'utente.
     */
    public void setProfessione(String professione) {
        this.professione = professione;
    }

    /**
     * Restituisce la citt&agrave in cui abita l'utente.
     *
     * @return la citt&agrave in cui abita l'utente.
     */
    public String getCitta() {
        return (citta == null ? "" : citta);
    }

    /**
     * Imposta la citt&agrave in cui abita l'utente.
     *
     * @param citta la citt&agrave in cui abita l'utente.
     */
    public void setCitta(String citta) {
        this.citta = citta;
    }

    /**
     * Restituisce il cognome dell'utente.
     *
     * @return il cognome dell'utente.
     */
    public String getCognome() {
        return cognome;
    }

    /**
     * Imposta il cognome dell'utente.
     *
     * @param cognome il cognome dell'utente.
     */
    public void setCognome(String cognome) {
        this.cognome = cognome;
    }

    /**
     * Restituisce il nome dell'utente.
     *
     * @return il nome dell'utente.
     */
    public String getNome() {
        return nome;
    }

    /**
     * Imposta il nome dell'utente.
     *
     * @param nome il nome dell'utente.
     */
    public void setNome(String nome) {
        this.nome = nome;
    }

    /**
     * Restituisce la password dell'utente.
     *
     * @return la password dell'utente.
     */
    public String getPassword() {
        return password;
    }

    /**
     * Imposta la password dell'utente.
     *
     * @param password la password dell'utente.
     */
    public void setPassword(String password) {
        this.password = password;
    }

    /**
     * Restituisce lo username dell'utente.
     *
     * @return lo username dell'utente.
     */
    public String getUsername() {
        return username;
    }

    /**
     * Imposta lo username dell'utente.
     *
     * @param username lo username dell'utente.
     */
    public void setUsername(String username) {
        this.username = username;
    }

    /**
     * Specifica se l'utente ha l'amico specificato come parametro.
     *
     * @param amico l'utente di cui verificare il legame di amicizia.
     * @return <code>true</code> se l'utente ha l'amico specificato,
     * <code>false</code> altrimenti.
     */
    public boolean hasAmico(Utente amico) {
        return amici.contains(amico);
    }

    /**
     * Aggiunge un amico alla lista di amici.
     *
     * @param amico l'amico da aggiungere.
     * @return <code>true</code> se l'amico &egrave stato aggiunto,
     * <code>false</code> se l'amico non &egrave stato aggiunto perch&eacute
     * era gi&agrave un amico dell'utente.
     */
    public boolean aggiungiAmico(Utente amico) {
        return amici.add(amico);
    }

    /**
     * Aggiunge un desiderio all'utente.
     *
     * @param desiderio il desiderio da aggiungere.
     */
    public void aggiungiDesiderio(Wish desiderio) {
        wishList.add(desiderio);
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (username != null ? username.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Utente)) {
            return false;
        }
        Utente other = (Utente) object;
        if ((this.username == null && other.username != null)
                || (this.username != null && !this.username.equals(other.username))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        String wishListStr = "[";
        String amiciStr = "[";

        for (Wish wish : wishList) {
            wishListStr += wish + ",";
        }
        if (wishList.size() == 0) {
            wishListStr += "]";
        } else {
            wishListStr = wishListStr.substring(0, wishListStr.length() - 1) + "]";
        }

        for (Utente amico : amici) {
            amiciStr += amico.getUsername() + ",";
        }
        if (amici.size() == 0) {
            amiciStr += "]";
        } else {
            amiciStr = amiciStr.substring(0, amiciStr.length() - 1) + "]";
        }

        return "entity.Utente[username=" + username + ", nome=" + nome
                + ", cognome=" + cognome + ", password=" + password
                + ", citta=" + citta + ", mail=" + mail + ", professione="
                + professione + ", wishList=" + wishListStr + ", amici=" + amiciStr + "]";
    }
}
